File: | var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/cxxalloc.h |
Warning: | line 60, column 10 Attempt to free released memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
2 | /* vim:expandtab:shiftwidth=2:tabstop=2: | |||
3 | */ | |||
4 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
7 | ||||
8 | #include "nsGNOMEShellSearchProvider.h" | |||
9 | ||||
10 | #include "nsToolkitCompsCID.h" | |||
11 | #include "nsIFaviconService.h" | |||
12 | #include "base/message_loop.h" // for MessageLoop | |||
13 | #include "base/task.h" // for NewRunnableMethod, etc | |||
14 | #include "mozilla/gfx/2D.h" | |||
15 | #include "nsComponentManagerUtils.h" | |||
16 | #include "nsIIOService.h" | |||
17 | #include "nsIURI.h" | |||
18 | #include "nsNetCID.h" | |||
19 | #include "nsPrintfCString.h" | |||
20 | #include "nsServiceManagerUtils.h" | |||
21 | #include "mozilla/GUniquePtr.h" | |||
22 | #include "mozilla/UniquePtrExtensions.h" | |||
23 | ||||
24 | #include "imgIContainer.h" | |||
25 | #include "imgITools.h" | |||
26 | ||||
27 | using namespace mozilla; | |||
28 | using namespace mozilla::gfx; | |||
29 | ||||
30 | // Mozilla has old GIO version in build roots | |||
31 | #define G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUEGBusNameOwnerFlags(1 << 2) GBusNameOwnerFlags(1 << 2) | |||
32 | ||||
33 | static const char* introspect_template = | |||
34 | "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection " | |||
35 | "1.0//EN\"\n" | |||
36 | "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" | |||
37 | "<node>\n" | |||
38 | " <interface name=\"org.gnome.Shell.SearchProvider2\">\n" | |||
39 | " <method name=\"GetInitialResultSet\">\n" | |||
40 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
41 | " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" | |||
42 | " </method>\n" | |||
43 | " <method name=\"GetSubsearchResultSet\">\n" | |||
44 | " <arg type=\"as\" name=\"previous_results\" direction=\"in\" />\n" | |||
45 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
46 | " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" | |||
47 | " </method>\n" | |||
48 | " <method name=\"GetResultMetas\">\n" | |||
49 | " <arg type=\"as\" name=\"identifiers\" direction=\"in\" />\n" | |||
50 | " <arg type=\"aa{sv}\" name=\"metas\" direction=\"out\" />\n" | |||
51 | " </method>\n" | |||
52 | " <method name=\"ActivateResult\">\n" | |||
53 | " <arg type=\"s\" name=\"identifier\" direction=\"in\" />\n" | |||
54 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
55 | " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" | |||
56 | " </method>\n" | |||
57 | " <method name=\"LaunchSearch\">\n" | |||
58 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
59 | " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" | |||
60 | " </method>\n" | |||
61 | "</interface>\n" | |||
62 | "</node>\n"; | |||
63 | ||||
64 | class AsyncFaviconDataReady final : public nsIFaviconDataCallback { | |||
65 | public: | |||
66 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: | |||
67 | NS_DECL_NSIFAVICONDATACALLBACKvirtual nsresult OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen , const uint8_t *aData, const nsACString& aMimeType, uint16_t aWidth) override; | |||
68 | ||||
69 | AsyncFaviconDataReady(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult, | |||
70 | int aIconIndex, int aTimeStamp) | |||
71 | : mSearchResult(std::move(aSearchResult)), | |||
72 | mIconIndex(aIconIndex), | |||
73 | mTimeStamp(aTimeStamp) {}; | |||
74 | ||||
75 | private: | |||
76 | ~AsyncFaviconDataReady() {} | |||
77 | ||||
78 | RefPtr<nsGNOMEShellHistorySearchResult> mSearchResult; | |||
79 | int mIconIndex; | |||
80 | int mTimeStamp; | |||
81 | }; | |||
82 | ||||
83 | NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)MozExternalRefCountType AsyncFaviconDataReady::AddRef(void) { static_assert(!std::is_destructible_v<AsyncFaviconDataReady >, "Reference-counted class " "AsyncFaviconDataReady" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("AsyncFaviconDataReady" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("AsyncFaviconDataReady" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"AsyncFaviconDataReady\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"AsyncFaviconDataReady\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("AsyncFaviconDataReady" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("AsyncFaviconDataReady" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType AsyncFaviconDataReady::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 83 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("AsyncFaviconDataReady" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("AsyncFaviconDataReady" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"AsyncFaviconDataReady\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"AsyncFaviconDataReady\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("AsyncFaviconDataReady" " not thread-safe"); const char* const nametmp = "AsyncFaviconDataReady"; nsrefcnt count = --mRefCnt ; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult AsyncFaviconDataReady::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<AsyncFaviconDataReady, nsIFaviconDataCallback >, int32_t( reinterpret_cast<char*>(static_cast<nsIFaviconDataCallback *>((AsyncFaviconDataReady*)0x1000)) - reinterpret_cast< char*>((AsyncFaviconDataReady*)0x1000))}, {&mozilla::detail ::kImplementedIID<AsyncFaviconDataReady, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIFaviconDataCallback*>((AsyncFaviconDataReady *)0x1000))) - reinterpret_cast<char*>((AsyncFaviconDataReady *)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr , table); return rv; } | |||
84 | ||||
85 | // Inspired by SurfaceToPackedBGRA | |||
86 | static UniquePtr<uint8_t[]> SurfaceToPackedRGBA(DataSourceSurface* aSurface) { | |||
87 | IntSize size = aSurface->GetSize(); | |||
88 | CheckedInt<size_t> bufferSize = | |||
89 | CheckedInt<size_t>(size.width * 4) * CheckedInt<size_t>(size.height); | |||
90 | if (!bufferSize.isValid()) { | |||
91 | return nullptr; | |||
92 | } | |||
93 | UniquePtr<uint8_t[]> imageBuffer(new (std::nothrow) | |||
94 | uint8_t[bufferSize.value()]); | |||
95 | if (!imageBuffer) { | |||
96 | return nullptr; | |||
97 | } | |||
98 | ||||
99 | DataSourceSurface::MappedSurface map; | |||
100 | if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { | |||
101 | return nullptr; | |||
102 | } | |||
103 | ||||
104 | // Convert BGRA to RGBA | |||
105 | uint32_t* aSrc = (uint32_t*)map.mData; | |||
106 | uint32_t* aDst = (uint32_t*)imageBuffer.get(); | |||
107 | for (int i = 0; i < size.width * size.height; i++, aDst++, aSrc++) { | |||
108 | *aDst = *aSrc & 0xff00ff00; | |||
109 | *aDst |= (*aSrc & 0xff) << 16; | |||
110 | *aDst |= (*aSrc & 0xff0000) >> 16; | |||
111 | } | |||
112 | ||||
113 | aSurface->Unmap(); | |||
114 | ||||
115 | return imageBuffer; | |||
116 | } | |||
117 | ||||
118 | NS_IMETHODIMPnsresult | |||
119 | AsyncFaviconDataReady::OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen, | |||
120 | const uint8_t* aData, | |||
121 | const nsACString& aMimeType, | |||
122 | uint16_t aWidth) { | |||
123 | // This is a callback from some previous search so we don't want it | |||
124 | if (mTimeStamp != mSearchResult->GetTimeStamp() || !aData || !aDataLen) { | |||
125 | return NS_ERROR_FAILURE; | |||
126 | } | |||
127 | ||||
128 | // Decode the image from the format it was returned to us in (probably PNG) | |||
129 | nsCOMPtr<imgIContainer> container; | |||
130 | nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); | |||
131 | nsresult rv = imgtool->DecodeImageFromBuffer( | |||
132 | reinterpret_cast<const char*>(aData), aDataLen, aMimeType, | |||
133 | getter_AddRefs(container)); | |||
134 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 134); return rv; } } while (false); | |||
135 | ||||
136 | RefPtr<SourceSurface> surface = container->GetFrame( | |||
137 | imgIContainer::FRAME_FIRST, | |||
138 | imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY); | |||
139 | ||||
140 | if (!surface || surface->GetFormat() != SurfaceFormat::B8G8R8A8) { | |||
141 | return NS_ERROR_FAILURE; | |||
142 | } | |||
143 | ||||
144 | // Allocate a new buffer that we own. | |||
145 | RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); | |||
146 | UniquePtr<uint8_t[]> data = SurfaceToPackedRGBA(dataSurface); | |||
147 | if (!data) { | |||
148 | return NS_ERROR_OUT_OF_MEMORY; | |||
149 | } | |||
150 | ||||
151 | mSearchResult->SetHistoryIcon(mTimeStamp, std::move(data), | |||
152 | surface->GetSize().width, | |||
153 | surface->GetSize().height, mIconIndex); | |||
154 | return NS_OK; | |||
155 | } | |||
156 | ||||
157 | void nsGNOMEShellSearchProvider::HandleSearchResultSet( | |||
158 | GVariant* aParameters, GDBusMethodInvocation* aInvocation, | |||
159 | bool aInitialSearch) { | |||
160 | // Discard any existing search results. | |||
161 | mSearchResult = nullptr; | |||
162 | ||||
163 | RefPtr<nsGNOMEShellHistorySearchResult> newSearch = | |||
164 | new nsGNOMEShellHistorySearchResult(this, mConnection, | |||
165 | mSearchResultTimeStamp); | |||
166 | mSearchResultTimeStamp++; | |||
167 | newSearch->SetTimeStamp(mSearchResultTimeStamp); | |||
168 | ||||
169 | // Send the search request over DBus. We'll get reply over DBus it will be | |||
170 | // set to mSearchResult by nsGNOMEShellSearchProvider::SetSearchResult(). | |||
171 | DBusHandleResultSet(newSearch.forget(), aParameters, aInitialSearch, | |||
172 | aInvocation); | |||
173 | } | |||
174 | ||||
175 | void nsGNOMEShellSearchProvider::HandleResultMetas( | |||
176 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
177 | if (mSearchResult) { | |||
178 | DBusHandleResultMetas(mSearchResult, aParameters, aInvocation); | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | void nsGNOMEShellSearchProvider::ActivateResult( | |||
183 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
184 | if (mSearchResult) { | |||
185 | DBusActivateResult(mSearchResult, aParameters, aInvocation); | |||
186 | } | |||
187 | } | |||
188 | ||||
189 | void nsGNOMEShellSearchProvider::LaunchSearch( | |||
190 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
191 | if (mSearchResult) { | |||
192 | DBusLaunchSearch(mSearchResult, aParameters, aInvocation); | |||
193 | } | |||
194 | } | |||
195 | ||||
196 | static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender, | |||
197 | const gchar* aObjectPath, | |||
198 | const gchar* aInterfaceName, | |||
199 | const gchar* aMethodName, GVariant* aParameters, | |||
200 | GDBusMethodInvocation* aInvocation, | |||
201 | gpointer aUserData) { | |||
202 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 202; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
203 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 203); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 203; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
204 | ||||
205 | if (strcmp("org.gnome.Shell.SearchProvider2", aInterfaceName) == 0) { | |||
206 | if (strcmp("GetInitialResultSet", aMethodName) == 0) { | |||
207 | static_cast<nsGNOMEShellSearchProvider*>(aUserData) | |||
208 | ->HandleSearchResultSet(aParameters, aInvocation, | |||
209 | /* aInitialSearch */ true); | |||
210 | } else if (strcmp("GetSubsearchResultSet", aMethodName) == 0) { | |||
211 | static_cast<nsGNOMEShellSearchProvider*>(aUserData) | |||
212 | ->HandleSearchResultSet(aParameters, aInvocation, | |||
213 | /* aInitialSearch */ false); | |||
214 | } else if (strcmp("GetResultMetas", aMethodName) == 0) { | |||
215 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->HandleResultMetas( | |||
216 | aParameters, aInvocation); | |||
217 | } else if (strcmp("ActivateResult", aMethodName) == 0) { | |||
218 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->ActivateResult( | |||
219 | aParameters, aInvocation); | |||
220 | } else if (strcmp("LaunchSearch", aMethodName) == 0) { | |||
221 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->LaunchSearch( | |||
222 | aParameters, aInvocation); | |||
223 | } else { | |||
224 | g_warning( | |||
225 | "nsGNOMEShellSearchProvider: HandleMethodCall() wrong method %s", | |||
226 | aMethodName); | |||
227 | } | |||
228 | } | |||
229 | } | |||
230 | ||||
231 | static GVariant* HandleGetProperty(GDBusConnection* aConnection, | |||
232 | const gchar* aSender, | |||
233 | const gchar* aObjectPath, | |||
234 | const gchar* aInterfaceName, | |||
235 | const gchar* aPropertyName, GError** aError, | |||
236 | gpointer aUserData) { | |||
237 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 237; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
238 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 238; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
239 | g_set_error(aError, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED, | |||
240 | "%s:%s setting is not supported", aInterfaceName, aPropertyName); | |||
241 | return nullptr; | |||
242 | } | |||
243 | ||||
244 | static gboolean HandleSetProperty(GDBusConnection* aConnection, | |||
245 | const gchar* aSender, | |||
246 | const gchar* aObjectPath, | |||
247 | const gchar* aInterfaceName, | |||
248 | const gchar* aPropertyName, GVariant* aValue, | |||
249 | GError** aError, gpointer aUserData) { | |||
250 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 250; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
251 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 251; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
252 | g_set_error(aError, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED, | |||
253 | "%s:%s setting is not supported", aInterfaceName, aPropertyName); | |||
254 | return false; | |||
255 | } | |||
256 | ||||
257 | static const GDBusInterfaceVTable gInterfaceVTable = { | |||
258 | HandleMethodCall, HandleGetProperty, HandleSetProperty}; | |||
259 | ||||
260 | void nsGNOMEShellSearchProvider::OnBusAcquired(GDBusConnection* aConnection) { | |||
261 | GUniquePtr<GError> error; | |||
262 | mIntrospectionData = dont_AddRef(g_dbus_node_info_new_for_xml( | |||
263 | introspect_template, getter_Transfers(error))); | |||
264 | if (!mIntrospectionData) { | |||
265 | g_warning( | |||
266 | "nsGNOMEShellSearchProvider: g_dbus_node_info_new_for_xml() failed! %s", | |||
267 | error->message); | |||
268 | return; | |||
269 | } | |||
270 | ||||
271 | mRegistrationId = g_dbus_connection_register_object( | |||
272 | aConnection, GetDBusObjectPath(), mIntrospectionData->interfaces[0], | |||
273 | &gInterfaceVTable, this, /* user_data */ | |||
274 | nullptr, /* user_data_free_func */ | |||
275 | getter_Transfers(error)); /* GError** */ | |||
276 | ||||
277 | if (mRegistrationId == 0) { | |||
278 | g_warning( | |||
279 | "nsGNOMEShellSearchProvider: g_dbus_connection_register_object() " | |||
280 | "failed! %s", | |||
281 | error->message); | |||
282 | return; | |||
283 | } | |||
284 | } | |||
285 | ||||
286 | void nsGNOMEShellSearchProvider::OnNameAcquired(GDBusConnection* aConnection) { | |||
287 | mConnection = aConnection; | |||
288 | } | |||
289 | ||||
290 | void nsGNOMEShellSearchProvider::OnNameLost(GDBusConnection* aConnection) { | |||
291 | mConnection = nullptr; | |||
292 | if (!mRegistrationId) { | |||
293 | return; | |||
294 | } | |||
295 | if (g_dbus_connection_unregister_object(aConnection, mRegistrationId)) { | |||
296 | mRegistrationId = 0; | |||
297 | } | |||
298 | } | |||
299 | ||||
300 | nsresult nsGNOMEShellSearchProvider::Startup() { | |||
301 | if (mDBusID) { | |||
302 | // We're already connected so we don't need to reconnect | |||
303 | return NS_ERROR_ALREADY_INITIALIZED; | |||
304 | } | |||
305 | ||||
306 | mDBusID = g_bus_own_name( | |||
307 | G_BUS_TYPE_SESSION, GetDBusBusName(), G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUEGBusNameOwnerFlags(1 << 2), | |||
308 | [](GDBusConnection* aConnection, const gchar*, | |||
309 | gpointer aUserData) -> void { | |||
310 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnBusAcquired( | |||
311 | aConnection); | |||
312 | }, | |||
313 | [](GDBusConnection* aConnection, const gchar*, | |||
314 | gpointer aUserData) -> void { | |||
315 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameAcquired( | |||
316 | aConnection); | |||
317 | }, | |||
318 | [](GDBusConnection* aConnection, const gchar*, | |||
319 | gpointer aUserData) -> void { | |||
320 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameLost( | |||
321 | aConnection); | |||
322 | }, | |||
323 | this, nullptr); | |||
324 | ||||
325 | if (!mDBusID) { | |||
326 | g_warning("nsGNOMEShellSearchProvider: g_bus_own_name() failed!"); | |||
327 | return NS_ERROR_FAILURE; | |||
328 | } | |||
329 | ||||
330 | mSearchResultTimeStamp = 0; | |||
331 | return NS_OK; | |||
332 | } | |||
333 | ||||
334 | void nsGNOMEShellSearchProvider::Shutdown() { | |||
335 | OnNameLost(mConnection); | |||
336 | if (mDBusID) { | |||
337 | g_bus_unown_name(mDBusID); | |||
338 | mDBusID = 0; | |||
339 | } | |||
340 | mIntrospectionData = nullptr; | |||
341 | } | |||
342 | ||||
343 | bool nsGNOMEShellSearchProvider::SetSearchResult( | |||
344 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) { | |||
345 | MOZ_ASSERT(!mSearchResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mSearchResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!mSearchResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mSearchResult" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mSearchResult" ")"); do { *((volatile int*)__null) = 345; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
346 | ||||
347 | if (mSearchResultTimeStamp != aSearchResult->GetTimeStamp()) { | |||
348 | NS_WARNING("Time stamp mismatch.")NS_DebugBreak(NS_DEBUG_WARNING, "Time stamp mismatch.", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 348); | |||
349 | return false; | |||
350 | } | |||
351 | mSearchResult = aSearchResult; | |||
352 | return true; | |||
353 | } | |||
354 | ||||
355 | static void DispatchSearchResults( | |||
356 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult, | |||
357 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) { | |||
358 | aSearchResult->ReceiveSearchResultContainer(aHistResultContainer); | |||
359 | } | |||
360 | ||||
361 | nsresult nsGNOMEShellHistoryService::QueryHistory( | |||
362 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) { | |||
363 | if (!mHistoryService) { | |||
364 | mHistoryService = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID"@mozilla.org/browser/nav-history-service;1"); | |||
365 | if (!mHistoryService) { | |||
366 | return NS_ERROR_FAILURE; | |||
367 | } | |||
368 | } | |||
369 | ||||
370 | nsresult rv; | |||
371 | nsCOMPtr<nsINavHistoryQuery> histQuery; | |||
372 | rv = mHistoryService->GetNewQuery(getter_AddRefs(histQuery)); | |||
373 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 373); return rv; } } while (false); | |||
374 | ||||
375 | rv = histQuery->SetSearchTerms( | |||
376 | NS_ConvertUTF8toUTF16(aSearchResult->GetSearchTerm())); | |||
377 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 377); return rv; } } while (false); | |||
378 | ||||
379 | nsCOMPtr<nsINavHistoryQueryOptions> histQueryOpts; | |||
380 | rv = mHistoryService->GetNewQueryOptions(getter_AddRefs(histQueryOpts)); | |||
381 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 381); return rv; } } while (false); | |||
382 | ||||
383 | rv = histQueryOpts->SetSortingMode( | |||
384 | nsINavHistoryQueryOptions::SORT_BY_FRECENCY_DESCENDING); | |||
385 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 385); return rv; } } while (false); | |||
386 | ||||
387 | rv = histQueryOpts->SetMaxResults(MAX_SEARCH_RESULTS_NUM9); | |||
388 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 388); return rv; } } while (false); | |||
389 | ||||
390 | nsCOMPtr<nsINavHistoryResult> histResult; | |||
391 | rv = mHistoryService->ExecuteQuery(histQuery, histQueryOpts, | |||
392 | getter_AddRefs(histResult)); | |||
393 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 393); return rv; } } while (false); | |||
394 | ||||
395 | nsCOMPtr<nsINavHistoryContainerResultNode> resultContainer; | |||
396 | ||||
397 | rv = histResult->GetRoot(getter_AddRefs(resultContainer)); | |||
398 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 398); return rv; } } while (false); | |||
399 | ||||
400 | rv = resultContainer->SetContainerOpen(true); | |||
401 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 401); return rv; } } while (false); | |||
402 | ||||
403 | // Simulate async searching by delayed reply. This search API will | |||
404 | // likely become async in the future and we want to be sure to not rely on | |||
405 | // its current synchronous behavior. | |||
406 | MOZ_ASSERT(MessageLoop::current())do { static_assert( mozilla::detail::AssertionConditionType< decltype(MessageLoop::current())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(MessageLoop::current()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("MessageLoop::current()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "MessageLoop::current()" ")"); do { *((volatile int*)__null) = 406; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
407 | MessageLoop::current()->PostTask( | |||
408 | NewRunnableFunction("Gnome shell search results", &DispatchSearchResults, | |||
409 | aSearchResult, resultContainer)); | |||
410 | ||||
411 | return NS_OK; | |||
412 | } | |||
413 | ||||
414 | static void DBusGetIDKeyForURI(int aIndex, nsAutoCString& aUri, | |||
415 | nsAutoCString& aIDKey) { | |||
416 | // Compose ID as NN:URL where NN is index to our current history | |||
417 | // result container. | |||
418 | aIDKey = nsPrintfCString("%.2d:%s", aIndex, aUri.get()); | |||
419 | } | |||
420 | ||||
421 | // Send (as) rearch result reply | |||
422 | void nsGNOMEShellHistorySearchResult::HandleSearchResultReply() { | |||
423 | MOZ_ASSERT(mReply)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mReply)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(mReply))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mReply", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 423); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mReply" ")") ; do { *((volatile int*)__null) = 423; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
424 | ||||
425 | GVariantBuilder b; | |||
426 | g_variant_builder_init(&b, G_VARIANT_TYPE("as")(g_variant_type_checked_ (("as")))); | |||
427 | ||||
428 | uint32_t childCount = 0; | |||
429 | nsresult rv = mHistResultContainer->GetChildCount(&childCount); | |||
430 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && childCount > 0) { | |||
431 | // Obtain the favicon service and get the favicon for the specified page | |||
432 | nsCOMPtr<nsIFaviconService> favIconSvc( | |||
433 | do_GetService("@mozilla.org/browser/favicon-service;1")); | |||
434 | nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID"@mozilla.org/network/io-service;1")); | |||
435 | ||||
436 | if (childCount > MAX_SEARCH_RESULTS_NUM9) { | |||
437 | childCount = MAX_SEARCH_RESULTS_NUM9; | |||
438 | } | |||
439 | ||||
440 | for (uint32_t i = 0; i < childCount; i++) { | |||
441 | nsCOMPtr<nsINavHistoryResultNode> child; | |||
442 | rv = mHistResultContainer->GetChild(i, getter_AddRefs(child)); | |||
443 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 443)) { | |||
444 | continue; | |||
445 | } | |||
446 | if (!IsHistoryResultNodeURI(child)) { | |||
447 | continue; | |||
448 | } | |||
449 | ||||
450 | nsAutoCString uri; | |||
451 | child->GetUri(uri); | |||
452 | ||||
453 | nsCOMPtr<nsIURI> iconIri; | |||
454 | ios->NewURI(uri, nullptr, nullptr, getter_AddRefs(iconIri)); | |||
455 | nsCOMPtr<nsIFaviconDataCallback> callback = | |||
456 | new AsyncFaviconDataReady(this, i, mTimeStamp); | |||
457 | favIconSvc->GetFaviconDataForPage(iconIri, callback, 0); | |||
458 | ||||
459 | nsAutoCString idKey; | |||
460 | DBusGetIDKeyForURI(i, uri, idKey); | |||
461 | ||||
462 | g_variant_builder_add(&b, "s", idKey.get()); | |||
463 | } | |||
464 | } | |||
465 | ||||
466 | nsPrintfCString searchString("%s:%s", KEYWORD_SEARCH_STRING"special:search", | |||
467 | mSearchTerm.get()); | |||
468 | g_variant_builder_add(&b, "s", searchString.get()); | |||
469 | ||||
470 | GVariant* v = g_variant_builder_end(&b); | |||
471 | g_dbus_method_invocation_return_value(mReply, g_variant_new_tuple(&v, 1)); | |||
472 | mReply = nullptr; | |||
473 | } | |||
474 | ||||
475 | void nsGNOMEShellHistorySearchResult::ReceiveSearchResultContainer( | |||
476 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) { | |||
477 | // Propagate search results to nsGNOMEShellSearchProvider. | |||
478 | // SetSearchResult() checks this is up-to-date search (our time stamp matches | |||
479 | // latest requested search timestamp). | |||
480 | if (mSearchProvider->SetSearchResult(this)) { | |||
481 | mHistResultContainer = aHistResultContainer; | |||
482 | HandleSearchResultReply(); | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | void nsGNOMEShellHistorySearchResult::SetHistoryIcon(int aTimeStamp, | |||
487 | UniquePtr<uint8_t[]> aData, | |||
488 | int aWidth, int aHeight, | |||
489 | int aIconIndex) { | |||
490 | MOZ_ASSERT(mTimeStamp == aTimeStamp)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mTimeStamp == aTimeStamp)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mTimeStamp == aTimeStamp))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mTimeStamp == aTimeStamp" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTimeStamp == aTimeStamp" ")"); do { *((volatile int*)__null) = 490; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| ||||
491 | MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aIconIndex < 9)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aIconIndex < 9))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIconIndex < 9" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 491); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aIconIndex < 9" ")"); do { *((volatile int*)__null) = 491; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
492 | mHistoryIcons[aIconIndex].Set(mTimeStamp, std::move(aData), aWidth, aHeight); | |||
493 | } | |||
494 | ||||
495 | GnomeHistoryIcon* nsGNOMEShellHistorySearchResult::GetHistoryIcon( | |||
496 | int aIconIndex) { | |||
497 | MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aIconIndex < 9)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aIconIndex < 9))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIconIndex < 9" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 497); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aIconIndex < 9" ")"); do { *((volatile int*)__null) = 497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
498 | if (mHistoryIcons[aIconIndex].GetTimeStamp() == mTimeStamp && | |||
499 | mHistoryIcons[aIconIndex].IsLoaded()) { | |||
500 | return mHistoryIcons + aIconIndex; | |||
501 | } | |||
502 | return nullptr; | |||
503 | } | |||
504 | ||||
505 | nsGNOMEShellHistoryService* GetGNOMEShellHistoryService() { | |||
506 | static nsGNOMEShellHistoryService gGNOMEShellHistoryService; | |||
507 | return &gGNOMEShellHistoryService; | |||
508 | } |
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | /* vim:expandtab:shiftwidth=2:tabstop=2: |
3 | */ |
4 | /* This Source Code Form is subject to the terms of the Mozilla Public |
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | |
8 | #ifndef __nsGNOMEShellSearchProvider_h__ |
9 | #define __nsGNOMEShellSearchProvider_h__ |
10 | |
11 | #include <gio/gio.h> |
12 | |
13 | #include "mozilla/RefPtr.h" |
14 | #include "mozilla/GRefPtr.h" |
15 | #include "mozilla/Span.h" |
16 | #include "nsINavHistoryService.h" |
17 | #include "nsUnixRemoteServer.h" |
18 | #include "nsString.h" |
19 | #include "nsCOMPtr.h" |
20 | #include "mozilla/UniquePtr.h" |
21 | #include "nsGNOMEShellDBusHelper.h" |
22 | |
23 | class nsGNOMEShellSearchProvider; |
24 | |
25 | class GnomeHistoryIcon { |
26 | public: |
27 | GnomeHistoryIcon() : mTimeStamp(-1), mWidth(0), mHeight(0) {}; |
28 | |
29 | // From which search is this icon |
30 | void Set(int aTimeStamp, mozilla::UniquePtr<uint8_t[]> aData, int aWidth, |
31 | int aHeight) { |
32 | mTimeStamp = aTimeStamp; |
33 | mWidth = aWidth; |
34 | mHeight = aHeight; |
35 | mData = std::move(aData); |
36 | } |
37 | |
38 | bool IsLoaded() { return mData && mWidth > 0 && mHeight > 0; } |
39 | int GetTimeStamp() { return mTimeStamp; } |
40 | uint8_t* GetData() { return mData.get(); } |
41 | int GetWidth() { return mWidth; } |
42 | int GetHeight() { return mHeight; } |
43 | |
44 | private: |
45 | int mTimeStamp; |
46 | mozilla::UniquePtr<uint8_t[]> mData; |
47 | int mWidth; |
48 | int mHeight; |
49 | }; |
50 | |
51 | // nsGNOMEShellHistorySearchResult is a container with contains search results |
52 | // which are files asynchronously by nsGNOMEShellHistoryService. |
53 | // The search results can be opened by Firefox then. |
54 | class nsGNOMEShellHistorySearchResult : public nsUnixRemoteServer { |
55 | public: |
56 | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsGNOMEShellHistorySearchResult)public: MozExternalRefCountType AddRef(void) { static_assert( !std::is_destructible_v<nsGNOMEShellHistorySearchResult> , "Reference-counted class " "nsGNOMEShellHistorySearchResult" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.h" , 56); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 56; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this ), (count), ("nsGNOMEShellHistorySearchResult"), (uint32_t)(sizeof (*this))); return (nsrefcnt)count; } MozExternalRefCountType Release (void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.h" , 56); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 56 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); nsrefcnt count = --mRefCnt; NS_LogRelease((this), ( count), ("nsGNOMEShellHistorySearchResult")); if (count == 0) { delete (this); return 0; } return count; } using HasThreadSafeRefCnt = std::true_type; protected: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; public: |
57 | |
58 | nsGNOMEShellHistorySearchResult(nsGNOMEShellSearchProvider* aSearchProvider, |
59 | GDBusConnection* aConnection, int aTimeStamp) |
60 | : mSearchProvider(aSearchProvider), |
61 | mConnection(aConnection), |
62 | mTimeStamp(aTimeStamp) {}; |
63 | |
64 | void SetReply(RefPtr<GDBusMethodInvocation> aReply) { |
65 | mReply = std::move(aReply); |
66 | } |
67 | void SetSearchTerm(const char* aSearchTerm) { |
68 | mSearchTerm = nsAutoCString(aSearchTerm); |
69 | } |
70 | GDBusConnection* GetDBusConnection() { return mConnection; } |
71 | void SetTimeStamp(int aTimeStamp) { mTimeStamp = aTimeStamp; } |
72 | int GetTimeStamp() { return mTimeStamp; } |
73 | nsAutoCString& GetSearchTerm() { return mSearchTerm; } |
74 | |
75 | // Receive (asynchronously) history search results from history service. |
76 | // This is called asynchronously by nsGNOMEShellHistoryService |
77 | // when we have search results available. |
78 | void ReceiveSearchResultContainer( |
79 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer); |
80 | |
81 | nsCOMPtr<nsINavHistoryContainerResultNode> GetSearchResultContainer() { |
82 | return mHistResultContainer; |
83 | } |
84 | void HandleCommandLine(mozilla::Span<const char> aBuffer, |
85 | uint32_t aTimestamp) { |
86 | nsUnixRemoteServer::HandleCommandLine(aBuffer, aTimestamp); |
87 | } |
88 | |
89 | void SetHistoryIcon(int aTimeStamp, mozilla::UniquePtr<uint8_t[]> aData, |
90 | int aWidth, int aHeight, int aIconIndex); |
91 | GnomeHistoryIcon* GetHistoryIcon(int aIconIndex); |
92 | |
93 | private: |
94 | void HandleSearchResultReply(); |
95 | |
96 | ~nsGNOMEShellHistorySearchResult() = default; |
97 | |
98 | private: |
99 | nsGNOMEShellSearchProvider* mSearchProvider; |
100 | nsCOMPtr<nsINavHistoryContainerResultNode> mHistResultContainer; |
101 | nsAutoCString mSearchTerm; |
102 | RefPtr<GDBusMethodInvocation> mReply; |
103 | GDBusConnection* mConnection = nullptr; |
104 | int mTimeStamp; |
105 | GnomeHistoryIcon mHistoryIcons[MAX_SEARCH_RESULTS_NUM9]; |
106 | }; |
107 | |
108 | class nsGNOMEShellHistoryService { |
109 | public: |
110 | nsresult QueryHistory(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult); |
111 | |
112 | private: |
113 | nsCOMPtr<nsINavHistoryService> mHistoryService; |
114 | }; |
115 | |
116 | class nsGNOMEShellSearchProvider { |
117 | public: |
118 | nsGNOMEShellSearchProvider() |
119 | : mConnection(nullptr), mSearchResultTimeStamp(0) {} |
120 | ~nsGNOMEShellSearchProvider() { Shutdown(); } |
121 | |
122 | nsresult Startup(); |
123 | void Shutdown(); |
124 | |
125 | void UnregisterDBusInterface(GDBusConnection* aConnection); |
126 | |
127 | bool SetSearchResult(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult); |
128 | |
129 | void HandleSearchResultSet(GVariant* aParameters, |
130 | GDBusMethodInvocation* aInvocation, |
131 | bool aInitialSearch); |
132 | void HandleResultMetas(GVariant* aParameters, |
133 | GDBusMethodInvocation* aInvocation); |
134 | void ActivateResult(GVariant* aParameters, |
135 | GDBusMethodInvocation* aInvocation); |
136 | void LaunchSearch(GVariant* aParameters, GDBusMethodInvocation* aInvocation); |
137 | |
138 | void OnBusAcquired(GDBusConnection* aConnection); |
139 | void OnNameAcquired(GDBusConnection* aConnection); |
140 | void OnNameLost(GDBusConnection* aConnection); |
141 | |
142 | private: |
143 | // The connection is owned by DBus library |
144 | uint mDBusID = 0; |
145 | uint mRegistrationId = 0; |
146 | GDBusConnection* mConnection = nullptr; |
147 | RefPtr<GDBusNodeInfo> mIntrospectionData; |
148 | |
149 | RefPtr<nsGNOMEShellHistorySearchResult> mSearchResult; |
150 | int mSearchResultTimeStamp; |
151 | }; |
152 | |
153 | nsGNOMEShellHistoryService* GetGNOMEShellHistoryService(); |
154 | |
155 | #endif // __nsGNOMEShellSearchProvider_h__ |
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | |
7 | /* Smart pointer managing sole ownership of a resource. */ |
8 | |
9 | #ifndef mozilla_UniquePtr_h |
10 | #define mozilla_UniquePtr_h |
11 | |
12 | #include <memory> |
13 | #include <type_traits> |
14 | #include <utility> |
15 | |
16 | #include "mozilla/Assertions.h" |
17 | #include "mozilla/Attributes.h" |
18 | #include "mozilla/CompactPair.h" |
19 | #include "mozilla/Compiler.h" |
20 | |
21 | namespace mozilla { |
22 | |
23 | template <typename T> |
24 | class DefaultDelete; |
25 | template <typename T, class D = DefaultDelete<T>> |
26 | class UniquePtr; |
27 | |
28 | } // namespace mozilla |
29 | |
30 | namespace mozilla { |
31 | |
32 | namespace detail { |
33 | |
34 | struct HasPointerTypeHelper { |
35 | template <class U> |
36 | static double Test(...); |
37 | template <class U> |
38 | static char Test(typename U::pointer* = 0); |
39 | }; |
40 | |
41 | template <class T> |
42 | class HasPointerType |
43 | : public std::integral_constant<bool, sizeof(HasPointerTypeHelper::Test<T>( |
44 | 0)) == 1> {}; |
45 | |
46 | template <class T, class D, bool = HasPointerType<D>::value> |
47 | struct PointerTypeImpl { |
48 | typedef typename D::pointer Type; |
49 | }; |
50 | |
51 | template <class T, class D> |
52 | struct PointerTypeImpl<T, D, false> { |
53 | typedef T* Type; |
54 | }; |
55 | |
56 | template <class T, class D> |
57 | struct PointerType { |
58 | typedef typename PointerTypeImpl<T, std::remove_reference_t<D>>::Type Type; |
59 | }; |
60 | |
61 | } // namespace detail |
62 | |
63 | /** |
64 | * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be |
65 | * transferred out of a UniquePtr through explicit action, but otherwise the |
66 | * resource is destroyed when the UniquePtr is destroyed. |
67 | * |
68 | * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr |
69 | * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr |
70 | * obviously *can't* copy ownership of its singly-owned resource. So what |
71 | * happens if you try to copy one? Bizarrely, ownership is implicitly |
72 | * *transferred*, preserving single ownership but breaking code that assumes a |
73 | * copy of an object is identical to the original. (This is why auto_ptr is |
74 | * prohibited in STL containers.) |
75 | * |
76 | * UniquePtr solves this problem by being *movable* rather than copyable. |
77 | * Instead of passing a |UniquePtr u| directly to the constructor or assignment |
78 | * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* |
79 | * ownership out of |u|, into the target of the construction/assignment. After |
80 | * the transfer completes, |u| contains |nullptr| and may be safely destroyed. |
81 | * This preserves single ownership but also allows UniquePtr to be moved by |
82 | * algorithms that have been made move-safe. (Note: if |u| is instead a |
83 | * temporary expression, don't use |Move()|: just pass the expression, because |
84 | * it's already move-ready. For more information see Move.h.) |
85 | * |
86 | * UniquePtr is also better than std::auto_ptr in that the deletion operation is |
87 | * customizable. An optional second template parameter specifies a class that |
88 | * (through its operator()(T*)) implements the desired deletion policy. If no |
89 | * policy is specified, mozilla::DefaultDelete<T> is used -- which will either |
90 | * |delete| or |delete[]| the resource, depending whether the resource is an |
91 | * array. Custom deletion policies ideally should be empty classes (no member |
92 | * fields, no member fields in base classes, no virtual methods/inheritance), |
93 | * because then UniquePtr can be just as efficient as a raw pointer. |
94 | * |
95 | * Use of UniquePtr proceeds like so: |
96 | * |
97 | * UniquePtr<int> g1; // initializes to nullptr |
98 | * g1.reset(new int); // switch resources using reset() |
99 | * g1 = nullptr; // clears g1, deletes the int |
100 | * |
101 | * UniquePtr<int> g2(new int); // owns that int |
102 | * int* p = g2.release(); // g2 leaks its int -- still requires deletion |
103 | * delete p; // now freed |
104 | * |
105 | * struct S { int x; S(int x) : x(x) {} }; |
106 | * UniquePtr<S> g3, g4(new S(5)); |
107 | * g3 = std::move(g4); // g3 owns the S, g4 cleared |
108 | * S* p = g3.get(); // g3 still owns |p| |
109 | * assert(g3->x == 5); // operator-> works (if .get() != nullptr) |
110 | * assert((*g3).x == 5); // also operator* (again, if not cleared) |
111 | * std::swap(g3, g4); // g4 now owns the S, g3 cleared |
112 | * g3.swap(g4); // g3 now owns the S, g4 cleared |
113 | * UniquePtr<S> g5(std::move(g3)); // g5 owns the S, g3 cleared |
114 | * g5.reset(); // deletes the S, g5 cleared |
115 | * |
116 | * struct FreePolicy { void operator()(void* p) { free(p); } }; |
117 | * UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int)))); |
118 | * int* ptr = g6.get(); |
119 | * g6 = nullptr; // calls free(ptr) |
120 | * |
121 | * Now, carefully note a few things you *can't* do: |
122 | * |
123 | * UniquePtr<int> b1; |
124 | * b1 = new int; // BAD: can only assign another UniquePtr |
125 | * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() |
126 | * |
127 | * UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr |
128 | * UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr |
129 | * |
130 | * (Note that changing a UniquePtr to store a direct |new| expression is |
131 | * permitted, but usually you should use MakeUnique, defined at the end of this |
132 | * header.) |
133 | * |
134 | * A few miscellaneous notes: |
135 | * |
136 | * UniquePtr, when not instantiated for an array type, can be move-constructed |
137 | * and move-assigned, not only from itself but from "derived" UniquePtr<U, E> |
138 | * instantiations where U converts to T and E converts to D. If you want to use |
139 | * this, you're going to have to specify a deletion policy for both UniquePtr |
140 | * instantations, and T pretty much has to have a virtual destructor. In other |
141 | * words, this doesn't work: |
142 | * |
143 | * struct Base { virtual ~Base() {} }; |
144 | * struct Derived : Base {}; |
145 | * |
146 | * UniquePtr<Base> b1; |
147 | * // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert |
148 | * UniquePtr<Derived> d1(std::move(b)); |
149 | * |
150 | * UniquePtr<Base> b2; |
151 | * UniquePtr<Derived, DefaultDelete<Base>> d2(std::move(b2)); // okay |
152 | * |
153 | * UniquePtr is specialized for array types. Specializing with an array type |
154 | * creates a smart-pointer version of that array -- not a pointer to such an |
155 | * array. |
156 | * |
157 | * UniquePtr<int[]> arr(new int[5]); |
158 | * arr[0] = 4; |
159 | * |
160 | * What else is different? Deletion of course uses |delete[]|. An operator[] |
161 | * is provided. Functionality that doesn't make sense for arrays is removed. |
162 | * The constructors and mutating methods only accept array pointers (not T*, U* |
163 | * that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|. |
164 | * |
165 | * It's perfectly okay for a function to return a UniquePtr. This transfers |
166 | * the UniquePtr's sole ownership of the data, to the fresh UniquePtr created |
167 | * in the calling function, that will then solely own that data. Such functions |
168 | * can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where |
169 | * |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere. |
170 | * |
171 | * UniquePtr will commonly be a member of a class, with lifetime equivalent to |
172 | * that of that class. If you want to expose the related resource, you could |
173 | * expose a raw pointer via |get()|, but ownership of a raw pointer is |
174 | * inherently unclear. So it's better to expose a |const UniquePtr&| instead. |
175 | * This prohibits mutation but still allows use of |get()| when needed (but |
176 | * operator-> is preferred). Of course, you can only use this smart pointer as |
177 | * long as the enclosing class instance remains live -- no different than if you |
178 | * exposed the |get()| raw pointer. |
179 | * |
180 | * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| |
181 | * argument. To specify an inout parameter (where the method may or may not |
182 | * take ownership of the resource, or reset it), or to specify an out parameter |
183 | * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| |
184 | * argument. To unconditionally transfer ownership of a UniquePtr |
185 | * into a method, use a |UniquePtr| argument. To conditionally transfer |
186 | * ownership of a resource into a method, should the method want it, use a |
187 | * |UniquePtr&&| argument. |
188 | */ |
189 | template <typename T, class D> |
190 | class UniquePtr { |
191 | public: |
192 | typedef T ElementType; |
193 | typedef D DeleterType; |
194 | typedef typename detail::PointerType<T, DeleterType>::Type Pointer; |
195 | |
196 | private: |
197 | mozilla::CompactPair<Pointer, DeleterType> mTuple; |
198 | |
199 | Pointer& ptr() { return mTuple.first(); } |
200 | const Pointer& ptr() const { return mTuple.first(); } |
201 | |
202 | DeleterType& del() { return mTuple.second(); } |
203 | const DeleterType& del() const { return mTuple.second(); } |
204 | |
205 | public: |
206 | /** |
207 | * Construct a UniquePtr containing |nullptr|. |
208 | */ |
209 | constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { |
210 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
211 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
212 | } |
213 | |
214 | /** |
215 | * Construct a UniquePtr containing |aPtr|. |
216 | */ |
217 | explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { |
218 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
219 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
220 | } |
221 | |
222 | UniquePtr(Pointer aPtr, |
223 | std::conditional_t<std::is_reference_v<D>, D, const D&> aD1) |
224 | : mTuple(aPtr, aD1) {} |
225 | |
226 | UniquePtr(Pointer aPtr, std::remove_reference_t<D>&& aD2) |
227 | : mTuple(aPtr, std::move(aD2)) { |
228 | static_assert(!std::is_reference_v<D>, |
229 | "rvalue deleter can't be stored by reference"); |
230 | } |
231 | |
232 | UniquePtr(UniquePtr&& aOther) |
233 | : mTuple(aOther.release(), |
234 | std::forward<DeleterType>(aOther.get_deleter())) {} |
235 | |
236 | MOZ_IMPLICIT constexpr UniquePtr(decltype(nullptr)) : UniquePtr() {} |
237 | |
238 | template <typename U, class E> |
239 | MOZ_IMPLICIT UniquePtr( |
240 | UniquePtr<U, E>&& aOther, |
241 | std::enable_if_t< |
242 | std::is_convertible_v<typename UniquePtr<U, E>::Pointer, Pointer> && |
243 | !std::is_array_v<U> && |
244 | (std::is_reference_v<D> ? std::is_same_v<D, E> |
245 | : std::is_convertible_v<E, D>), |
246 | int> |
247 | aDummy = 0) |
248 | : mTuple(aOther.release(), std::forward<E>(aOther.get_deleter())) {} |
249 | |
250 | ~UniquePtr() { reset(nullptr); } |
251 | |
252 | UniquePtr& operator=(UniquePtr&& aOther) { |
253 | reset(aOther.release()); |
254 | get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); |
255 | return *this; |
256 | } |
257 | |
258 | template <typename U, typename E> |
259 | UniquePtr& operator=(UniquePtr<U, E>&& aOther) { |
260 | static_assert( |
261 | std::is_convertible_v<typename UniquePtr<U, E>::Pointer, Pointer>, |
262 | "incompatible UniquePtr pointees"); |
263 | static_assert(!std::is_array_v<U>, |
264 | "can't assign from UniquePtr holding an array"); |
265 | |
266 | reset(aOther.release()); |
267 | get_deleter() = std::forward<E>(aOther.get_deleter()); |
268 | return *this; |
269 | } |
270 | |
271 | UniquePtr& operator=(decltype(nullptr)) { |
272 | reset(nullptr); |
273 | return *this; |
274 | } |
275 | |
276 | std::add_lvalue_reference_t<T> operator*() const { |
277 | MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr with *")do { static_assert( mozilla::detail::AssertionConditionType< decltype(get())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(get()))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("get()" " (" "dereferencing a UniquePtr containing nullptr with *" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h" , 277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "get()" ") (" "dereferencing a UniquePtr containing nullptr with *" ")"); do { *((volatile int*)__null) = 277; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
278 | return *get(); |
279 | } |
280 | Pointer operator->() const { |
281 | MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr with ->")do { static_assert( mozilla::detail::AssertionConditionType< decltype(get())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(get()))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("get()" " (" "dereferencing a UniquePtr containing nullptr with ->" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h" , 281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "get()" ") (" "dereferencing a UniquePtr containing nullptr with ->" ")" ); do { *((volatile int*)__null) = 281; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
282 | return get(); |
283 | } |
284 | |
285 | explicit operator bool() const { return get() != nullptr; } |
286 | |
287 | Pointer get() const { return ptr(); } |
288 | |
289 | DeleterType& get_deleter() { return del(); } |
290 | const DeleterType& get_deleter() const { return del(); } |
291 | |
292 | [[nodiscard]] Pointer release() { |
293 | Pointer p = ptr(); |
294 | ptr() = nullptr; |
295 | return p; |
296 | } |
297 | |
298 | void reset(Pointer aPtr = Pointer()) { |
299 | Pointer old = ptr(); |
300 | ptr() = aPtr; |
301 | if (old != nullptr) { |
302 | get_deleter()(old); |
303 | } |
304 | } |
305 | |
306 | void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } |
307 | |
308 | UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! |
309 | void operator=(const UniquePtr& aOther) = |
310 | delete; // assign using std::move()! |
311 | }; |
312 | |
313 | // In case you didn't read the comment by the main definition (you should!): the |
314 | // UniquePtr<T[]> specialization exists to manage array pointers. It deletes |
315 | // such pointers using delete[], it will reject construction and modification |
316 | // attempts using U* or U[]. Otherwise it works like the normal UniquePtr. |
317 | template <typename T, class D> |
318 | class UniquePtr<T[], D> { |
319 | public: |
320 | typedef T* Pointer; |
321 | typedef T ElementType; |
322 | typedef D DeleterType; |
323 | |
324 | private: |
325 | mozilla::CompactPair<Pointer, DeleterType> mTuple; |
326 | |
327 | public: |
328 | /** |
329 | * Construct a UniquePtr containing nullptr. |
330 | */ |
331 | constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { |
332 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
333 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
334 | } |
335 | |
336 | /** |
337 | * Construct a UniquePtr containing |aPtr|. |
338 | */ |
339 | explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { |
340 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
341 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
342 | } |
343 | |
344 | // delete[] knows how to handle *only* an array of a single class type. For |
345 | // delete[] to work correctly, it must know the size of each element, the |
346 | // fields and base classes of each element requiring destruction, and so on. |
347 | // So forbid all overloads which would end up invoking delete[] on a pointer |
348 | // of the wrong type. |
349 | template <typename U> |
350 | UniquePtr(U&& aU, |
351 | std::enable_if_t< |
352 | std::is_pointer_v<U> && std::is_convertible_v<U, Pointer>, int> |
353 | aDummy = 0) = delete; |
354 | |
355 | UniquePtr(Pointer aPtr, |
356 | std::conditional_t<std::is_reference_v<D>, D, const D&> aD1) |
357 | : mTuple(aPtr, aD1) {} |
358 | |
359 | UniquePtr(Pointer aPtr, std::remove_reference_t<D>&& aD2) |
360 | : mTuple(aPtr, std::move(aD2)) { |
361 | static_assert(!std::is_reference_v<D>, |
362 | "rvalue deleter can't be stored by reference"); |
363 | } |
364 | |
365 | // Forbidden for the same reasons as stated above. |
366 | template <typename U, typename V> |
367 | UniquePtr(U&& aU, V&& aV, |
368 | std::enable_if_t< |
369 | std::is_pointer_v<U> && std::is_convertible_v<U, Pointer>, int> |
370 | aDummy = 0) = delete; |
371 | |
372 | UniquePtr(UniquePtr&& aOther) |
373 | : mTuple(aOther.release(), |
374 | std::forward<DeleterType>(aOther.get_deleter())) {} |
375 | |
376 | MOZ_IMPLICIT |
377 | UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { |
378 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
379 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
380 | } |
381 | |
382 | ~UniquePtr() { reset(nullptr); } |
383 | |
384 | UniquePtr& operator=(UniquePtr&& aOther) { |
385 | reset(aOther.release()); |
386 | get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); |
387 | return *this; |
388 | } |
389 | |
390 | UniquePtr& operator=(decltype(nullptr)) { |
391 | reset(); |
392 | return *this; |
393 | } |
394 | |
395 | explicit operator bool() const { return get() != nullptr; } |
396 | |
397 | T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } |
398 | Pointer get() const { return mTuple.first(); } |
399 | |
400 | DeleterType& get_deleter() { return mTuple.second(); } |
401 | const DeleterType& get_deleter() const { return mTuple.second(); } |
402 | |
403 | [[nodiscard]] Pointer release() { |
404 | Pointer p = mTuple.first(); |
405 | mTuple.first() = nullptr; |
406 | return p; |
407 | } |
408 | |
409 | void reset(Pointer aPtr = Pointer()) { |
410 | Pointer old = mTuple.first(); |
411 | mTuple.first() = aPtr; |
412 | if (old != nullptr) { |
413 | mTuple.second()(old); |
414 | } |
415 | } |
416 | |
417 | void reset(decltype(nullptr)) { |
418 | Pointer old = mTuple.first(); |
419 | mTuple.first() = nullptr; |
420 | if (old != nullptr) { |
421 | mTuple.second()(old); |
422 | } |
423 | } |
424 | |
425 | template <typename U> |
426 | void reset(U) = delete; |
427 | |
428 | void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } |
429 | |
430 | UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! |
431 | void operator=(const UniquePtr& aOther) = |
432 | delete; // assign using std::move()! |
433 | }; |
434 | |
435 | /** |
436 | * A default deletion policy using plain old operator delete. |
437 | * |
438 | * Note that this type can be specialized, but authors should beware of the risk |
439 | * that the specialization may at some point cease to match (either because it |
440 | * gets moved to a different compilation unit or the signature changes). If the |
441 | * non-specialized (|delete|-based) version compiles for that type but does the |
442 | * wrong thing, bad things could happen. |
443 | * |
444 | * This is a non-issue for types which are always incomplete (i.e. opaque handle |
445 | * types), since |delete|-ing such a type will always trigger a compilation |
446 | * error. |
447 | */ |
448 | template <typename T> |
449 | class DefaultDelete { |
450 | public: |
451 | constexpr DefaultDelete() = default; |
452 | |
453 | template <typename U> |
454 | MOZ_IMPLICIT DefaultDelete( |
455 | const DefaultDelete<U>& aOther, |
456 | std::enable_if_t<std::is_convertible_v<U*, T*>, int> aDummy = 0) {} |
457 | |
458 | void operator()(T* aPtr) const { |
459 | static_assert(sizeof(T) > 0, "T must be complete"); |
460 | delete aPtr; |
461 | } |
462 | }; |
463 | |
464 | /** A default deletion policy using operator delete[]. */ |
465 | template <typename T> |
466 | class DefaultDelete<T[]> { |
467 | public: |
468 | constexpr DefaultDelete() = default; |
469 | |
470 | void operator()(T* aPtr) const { |
471 | static_assert(sizeof(T) > 0, "T must be complete"); |
472 | delete[] aPtr; |
473 | } |
474 | |
475 | template <typename U> |
476 | void operator()(U* aPtr) const = delete; |
477 | }; |
478 | |
479 | template <typename T, class D, typename U, class E> |
480 | bool operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { |
481 | return aX.get() == aY.get(); |
482 | } |
483 | |
484 | template <typename T, class D, typename U, class E> |
485 | bool operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { |
486 | return aX.get() != aY.get(); |
487 | } |
488 | |
489 | template <typename T, class D> |
490 | bool operator==(const UniquePtr<T, D>& aX, const T* aY) { |
491 | return aX.get() == aY; |
492 | } |
493 | |
494 | template <typename T, class D> |
495 | bool operator==(const T* aY, const UniquePtr<T, D>& aX) { |
496 | return aY == aX.get(); |
497 | } |
498 | |
499 | template <typename T, class D> |
500 | bool operator!=(const UniquePtr<T, D>& aX, const T* aY) { |
501 | return aX.get() != aY; |
502 | } |
503 | |
504 | template <typename T, class D> |
505 | bool operator!=(const T* aY, const UniquePtr<T, D>& aX) { |
506 | return aY != aX.get(); |
507 | } |
508 | |
509 | template <typename T, class D> |
510 | bool operator==(const UniquePtr<T, D>& aX, decltype(nullptr)) { |
511 | return !aX; |
512 | } |
513 | |
514 | template <typename T, class D> |
515 | bool operator==(decltype(nullptr), const UniquePtr<T, D>& aX) { |
516 | return !aX; |
517 | } |
518 | |
519 | template <typename T, class D> |
520 | bool operator!=(const UniquePtr<T, D>& aX, decltype(nullptr)) { |
521 | return bool(aX); |
522 | } |
523 | |
524 | template <typename T, class D> |
525 | bool operator!=(decltype(nullptr), const UniquePtr<T, D>& aX) { |
526 | return bool(aX); |
527 | } |
528 | |
529 | // No operator<, operator>, operator<=, operator>= for now because simplicity. |
530 | |
531 | namespace detail { |
532 | |
533 | template <typename T> |
534 | struct UniqueSelector { |
535 | typedef UniquePtr<T> SingleObject; |
536 | }; |
537 | |
538 | template <typename T> |
539 | struct UniqueSelector<T[]> { |
540 | typedef UniquePtr<T[]> UnknownBound; |
541 | }; |
542 | |
543 | template <typename T, decltype(sizeof(int)) N> |
544 | struct UniqueSelector<T[N]> { |
545 | typedef UniquePtr<T[N]> KnownBound; |
546 | }; |
547 | |
548 | } // namespace detail |
549 | |
550 | /** |
551 | * MakeUnique is a helper function for allocating new'd objects and arrays, |
552 | * returning a UniquePtr containing the resulting pointer. The semantics of |
553 | * MakeUnique<Type>(...) are as follows. |
554 | * |
555 | * If Type is an array T[n]: |
556 | * Disallowed, deleted, no overload for you! |
557 | * If Type is an array T[]: |
558 | * MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned |
559 | * is as if by |new T[n]()|, which value-initializes each element. (If T |
560 | * isn't a class type, this will zero each element. If T is a class type, |
561 | * then roughly speaking, each element will be constructed using its default |
562 | * constructor. See C++11 [dcl.init]p7 for the full gory details.) |
563 | * If Type is non-array T: |
564 | * The arguments passed to MakeUnique<T>(...) are forwarded into a |
565 | * |new T(...)| call, initializing the T as would happen if executing |
566 | * |T(...)|. |
567 | * |
568 | * There are various benefits to using MakeUnique instead of |new| expressions. |
569 | * |
570 | * First, MakeUnique eliminates use of |new| from code entirely. If objects are |
571 | * only created through UniquePtr, then (assuming all explicit release() calls |
572 | * are safe, including transitively, and no type-safety casting funniness) |
573 | * correctly maintained ownership of the UniquePtr guarantees no leaks are |
574 | * possible. (This pays off best if a class is only ever created through a |
575 | * factory method on the class, using a private constructor.) |
576 | * |
577 | * Second, initializing a UniquePtr using a |new| expression requires repeating |
578 | * the name of the new'd type, whereas MakeUnique in concert with the |auto| |
579 | * keyword names it only once: |
580 | * |
581 | * UniquePtr<char> ptr1(new char()); // repetitive |
582 | * auto ptr2 = MakeUnique<char>(); // shorter |
583 | * |
584 | * Of course this assumes the reader understands the operation MakeUnique |
585 | * performs. In the long run this is probably a reasonable assumption. In the |
586 | * short run you'll have to use your judgment about what readers can be expected |
587 | * to know, or to quickly look up. |
588 | * |
589 | * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In |
590 | * contrast you can't assign a pointer into a UniquePtr without using the |
591 | * cumbersome reset(). |
592 | * |
593 | * UniquePtr<char> p; |
594 | * p = new char; // ERROR |
595 | * p.reset(new char); // works, but fugly |
596 | * p = MakeUnique<char>(); // preferred |
597 | * |
598 | * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. |
599 | * An exception thrown after |new T| succeeds will leak that memory, unless the |
600 | * pointer is assigned to an object that will manage its ownership. UniquePtr |
601 | * ably serves this function.) |
602 | */ |
603 | |
604 | template <typename T, typename... Args> |
605 | typename detail::UniqueSelector<T>::SingleObject MakeUnique(Args&&... aArgs) { |
606 | return UniquePtr<T>(new T(std::forward<Args>(aArgs)...)); |
607 | } |
608 | |
609 | template <typename T> |
610 | typename detail::UniqueSelector<T>::UnknownBound MakeUnique( |
611 | decltype(sizeof(int)) aN) { |
612 | using ArrayType = std::remove_extent_t<T>; |
613 | return UniquePtr<T>(new ArrayType[aN]()); |
614 | } |
615 | |
616 | template <typename T, typename... Args> |
617 | typename detail::UniqueSelector<T>::KnownBound MakeUnique(Args&&... aArgs) = |
618 | delete; |
619 | |
620 | /** |
621 | * WrapUnique is a helper function to transfer ownership from a raw pointer |
622 | * into a UniquePtr<T>. It can only be used with a single non-array type. |
623 | * |
624 | * It is generally used this way: |
625 | * |
626 | * auto p = WrapUnique(new char); |
627 | * |
628 | * It can be used when MakeUnique is not usable, for example, when the |
629 | * constructor you are using is private, or you want to use aggregate |
630 | * initialization. |
631 | */ |
632 | |
633 | template <typename T> |
634 | typename detail::UniqueSelector<T>::SingleObject WrapUnique(T* aPtr) { |
635 | return UniquePtr<T>(aPtr); |
636 | } |
637 | |
638 | } // namespace mozilla |
639 | |
640 | namespace std { |
641 | |
642 | template <typename T, class D> |
643 | void swap(mozilla::UniquePtr<T, D>& aX, mozilla::UniquePtr<T, D>& aY) { |
644 | aX.swap(aY); |
645 | } |
646 | |
647 | } // namespace std |
648 | |
649 | /** |
650 | TempPtrToSetter(UniquePtr<T>*) -> T**-ish |
651 | TempPtrToSetter(std::unique_ptr<T>*) -> T**-ish |
652 | |
653 | Make a temporary class to support assigning to UniquePtr/unique_ptr via passing |
654 | a pointer to the callee. |
655 | |
656 | Often, APIs will be shaped like this trivial example: |
657 | ``` |
658 | nsresult Foo::NewChildBar(Bar** out) { |
659 | if (!IsOk()) return NS_ERROR_FAILURE; |
660 | *out = new Bar(this); |
661 | return NS_OK; |
662 | } |
663 | ``` |
664 | |
665 | In order to make this work with unique ptrs, it's often either risky or |
666 | overwrought: |
667 | ``` |
668 | Bar* bar = nullptr; |
669 | const auto cleanup = MakeScopeExit([&]() { |
670 | if (bar) { |
671 | delete bar; |
672 | } |
673 | }); |
674 | if (FAILED(foo->NewChildBar(&bar)) { |
675 | // handle it |
676 | } |
677 | ``` |
678 | |
679 | ``` |
680 | UniquePtr<Bar> bar; |
681 | { |
682 | Bar* raw = nullptr; |
683 | const auto res = foo->NewChildBar(&bar); |
684 | bar.reset(raw); |
685 | if (FAILED(res) { |
686 | // handle it |
687 | } |
688 | } |
689 | ``` |
690 | TempPtrToSettable is a shorthand for the latter approach, allowing something |
691 | cleaner but also safe: |
692 | |
693 | ``` |
694 | UniquePtr<Bar> bar; |
695 | if (FAILED(foo->NewChildBar(TempPtrToSetter(&bar))) { |
696 | // handle it |
697 | } |
698 | ``` |
699 | */ |
700 | |
701 | namespace mozilla { |
702 | namespace detail { |
703 | |
704 | template <class T, class UniquePtrT> |
705 | class MOZ_TEMPORARY_CLASS TempPtrToSetterT final { |
706 | private: |
707 | UniquePtrT* const mDest; |
708 | T* mNewVal; |
709 | |
710 | public: |
711 | explicit TempPtrToSetterT(UniquePtrT* dest) |
712 | : mDest(dest), mNewVal(mDest->get()) {} |
713 | |
714 | operator T**() { return &mNewVal; } |
715 | |
716 | ~TempPtrToSetterT() { |
717 | if (mDest->get() != mNewVal) { |
718 | mDest->reset(mNewVal); |
719 | } |
720 | } |
721 | }; |
722 | |
723 | } // namespace detail |
724 | |
725 | template <class T, class Deleter> |
726 | auto TempPtrToSetter(UniquePtr<T, Deleter>* const p) { |
727 | return detail::TempPtrToSetterT<T, UniquePtr<T, Deleter>>{p}; |
728 | } |
729 | |
730 | template <class T, class Deleter> |
731 | auto TempPtrToSetter(std::unique_ptr<T, Deleter>* const p) { |
732 | return detail::TempPtrToSetterT<T, std::unique_ptr<T, Deleter>>{p}; |
733 | } |
734 | |
735 | } // namespace mozilla |
736 | |
737 | #endif /* mozilla_UniquePtr_h */ |
1 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
4 | ||||
5 | #ifndef mozilla_cxxalloc_h | |||
6 | #define mozilla_cxxalloc_h | |||
7 | ||||
8 | /* | |||
9 | * We implement the default operators new/delete as part of | |||
10 | * libmozalloc, replacing their definitions in libstdc++. The | |||
11 | * operator new* definitions in libmozalloc will never return a NULL | |||
12 | * pointer. | |||
13 | * | |||
14 | * Each operator new immediately below returns a pointer to memory | |||
15 | * that can be delete'd by any of | |||
16 | * | |||
17 | * (1) the matching infallible operator delete immediately below | |||
18 | * (2) the matching system |operator delete(void*, std::nothrow)| | |||
19 | * (3) the matching system |operator delete(void*) noexcept(false)| | |||
20 | * | |||
21 | * NB: these are declared |noexcept(false)|, though they will never | |||
22 | * throw that exception. This declaration is consistent with the rule | |||
23 | * that |::operator new() noexcept(false)| will never return NULL. | |||
24 | * | |||
25 | * NB: mozilla::fallible can be used instead of std::nothrow. | |||
26 | */ | |||
27 | ||||
28 | #ifndef MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline | |||
29 | # define MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) | |||
30 | #endif | |||
31 | ||||
32 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size) noexcept(false) { | |||
33 | return moz_xmalloc(size); | |||
34 | } | |||
35 | ||||
36 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size, | |||
37 | const std::nothrow_t&) noexcept(true) { | |||
38 | return malloc_implmalloc(size); | |||
39 | } | |||
40 | ||||
41 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size) noexcept(false) { | |||
42 | return moz_xmalloc(size); | |||
43 | } | |||
44 | ||||
45 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size, | |||
46 | const std::nothrow_t&) noexcept(true) { | |||
47 | return malloc_implmalloc(size); | |||
48 | } | |||
49 | ||||
50 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr) noexcept(true) { | |||
51 | return free_implfree(ptr); | |||
52 | } | |||
53 | ||||
54 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, | |||
55 | const std::nothrow_t&) noexcept(true) { | |||
56 | return free_implfree(ptr); | |||
57 | } | |||
58 | ||||
59 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr) noexcept(true) { | |||
60 | return free_implfree(ptr); | |||
| ||||
61 | } | |||
62 | ||||
63 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[]( | |||
64 | void* ptr, const std::nothrow_t&) noexcept(true) { | |||
65 | return free_implfree(ptr); | |||
66 | } | |||
67 | ||||
68 | #if defined(XP_WIN) | |||
69 | // We provide the global sized delete overloads unconditionally because the | |||
70 | // MSVC runtime headers do, despite compiling with /Zc:sizedDealloc- | |||
71 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, | |||
72 | size_t /*size*/) noexcept(true) { | |||
73 | return free_implfree(ptr); | |||
74 | } | |||
75 | ||||
76 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr, | |||
77 | size_t /*size*/) noexcept(true) { | |||
78 | return free_implfree(ptr); | |||
79 | } | |||
80 | #endif | |||
81 | ||||
82 | #endif /* mozilla_cxxalloc_h */ |